﻿using System.Collections.Generic;
using System.Linq;

namespace AntBot
{
	public partial class FoodCollector
	{
		public enum StopReasons
		{
			InProgress,
			WorkComplete,
			Timeout,
			ExpandedNodesLimitHit
		}

		public struct FCNode
		{
			public int Steps;
			public int X;
			public int Y;
			public bool IsFood;

			public FCNode(FCNode node)
			{
				Steps = node.Steps;
				X = node.X;
				Y = node.Y;
				IsFood = node.IsFood;
			}

			public override string ToString()
			{
				return
					"Steps: " + Steps +
					" Location: " + new Location(X, Y) +
					" IsFood: " + IsFood;
			}
		}

		public struct FCUndo
		{
			public List<FCNode> SpawnedAnts;
			public FCNode StartAnt;
			public FCNode EndAnt;
		}

		public struct FCPosition
		{
			public FCScore Score;
			public byte Depth;
			public List<FCNode> Items;

			public int AntX;
			public int AntY;
			public int FoodX;
			public int FoodY;
			public int TurnsBefore;

			public override string ToString()
			{
				return "Score: " + Score + ", Items: " + (Items == null ? "0" : Items.Count.ToString());
			}

			public static FCPosition Clone(FCPosition source)
			{
				FCPosition pos = source;
				pos.Items = new List<FCNode>(source.Items.Count);
				foreach (FCNode fcNode in source.Items)
				{
					FCNode newNode = fcNode;
					pos.Items.Add(newNode);
				}
				return pos;
			}
		}

		public struct FCScore
		{
			public int Steps;
			public int FoodRemains;

			public FCScore(int steps, int foodRemains)
			{
				Steps = steps;
				FoodRemains = foodRemains;
			}

			public static bool operator ==(FCScore arg1, FCScore arg2)
			{
				return
					arg1.Steps == arg2.Steps &&
					arg1.FoodRemains == arg2.FoodRemains;
			}

			public static bool operator !=(FCScore arg1, FCScore arg2)
			{
				return !(arg1 == arg2);
			}

			public static bool operator >(FCScore arg1, FCScore arg2)
			{
				if (arg1.FoodRemains > arg2.FoodRemains)
					return true;
				if (arg1.FoodRemains < arg2.FoodRemains)
					return false;
				return arg1.Steps > arg2.Steps;
			}

			public static bool operator <(FCScore arg1, FCScore arg2)
			{
				if (arg1.FoodRemains < arg2.FoodRemains)
					return true;
				if (arg1.FoodRemains > arg2.FoodRemains)
					return false;
				return arg1.Steps < arg2.Steps;
			}

			public static FCScore MaxValue
			{
				get
				{
					return new FCScore(int.MaxValue, int.MaxValue);
				}
			}

			public override string ToString()
			{
				return Steps + " f:" + FoodRemains;
			}

			public override int GetHashCode()
			{
				return FoodRemains << 10 + Steps;
			}

			public bool Equals(FCScore other)
			{
				return other == this;
			}

			public override bool Equals(object obj)
			{
				if (obj is FCScore)
					return (FCScore)obj == this;
				return false;
			}
		}

		public struct FCMove
		{
			public FCNode Ant;
			public FCNode Food;
			public int ManhDistance { get; private set; }

			public FCMove(FCNode ant, FCNode food, int manhDist) : this()
			{
				Ant = ant;
				Food = food;
				ManhDistance = manhDist;
			}

			public FCMove(FCNode ant, FCNode food, State state)
				: this()
			{
				Ant = ant;
				Food = food;
				ManhDistance = state.Map.ManhattanDistance(ant.X, ant.Y, food.X, food.Y);
			}
		}

		internal class CompareFCNodeDistance : IComparer<FCMove>
		{
			#region IComparer Members
			public int Compare(FCMove a, FCMove b)
			{
				if (a.ManhDistance > b.ManhDistance) return 1;
				return a.ManhDistance == b.ManhDistance ? 0 : -1;
			}
			#endregion
		}
	}
}
